use crate::{isa::Isa, memory::Memory};

use std::{fs, io, path::Path};

use tracing::{error, info};

use num_traits::AsPrimitive;

pub struct Debugger<ISA: Isa> {
    mem: ISA::Memory,
    cpu: ISA::Cpu,
}

impl<ISA: Isa> Debugger<ISA> {
    pub fn new(cpu: ISA::Cpu, mem: ISA::Memory) -> Self {
        Debugger { cpu, mem }
    }

    pub fn load_img(&mut self, img: &Path) -> io::Result<()> {
        info!("load image {img:?}");
        let data = fs::read(img)?;

        if data.len() > self.mem.len() + ISA::Memory::BASE - ISA::PROG_START.as_() {
            use io::{Error, ErrorKind};
            error!("load too large image");
            return Err(Error::new(ErrorKind::OutOfMemory, "image is too large"));
        }
        for (i, v) in data.iter().enumerate() {
            self.mem.vaddr_write(i + ISA::PROG_START.as_(), *v);
        }
        info!("load image {img:?} succeed");
        Ok(())
    }

    pub fn run(&mut self) {
        ISA::exec(&mut self.cpu, &mut self.mem, usize::MAX);
        // use rustyline::Editor;
        // let mut rl = Editor::<()>::new();

        // loop {
        //     let readline = rl.readline(">> ");
        //     match readline {
        //         Ok(line) => {
        //             rl.add_history_entry(line.as_str());
        //             println!("Line: {}", line);
        //         }
        //         Err(e) => {
        //             panic!("sorry, readline error: {:?}", e);
        //         }
        //     }
        // }
    }
}
